#pragma once

#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include <unistd.h>
#include "Cond.hpp"
#include "Log.hpp"
#include "Mutex.hpp"
#include "Thread.hpp"
// #include "Task.hpp"

using namespace std;

namespace ThreadPoolModule
{
    using namespace CondModule;
    using namespace LogModule;
    using namespace LogModule;
    using namespace ThreadModule;

    // 用来做测试的线程方法
    void DefaultTest()
    {
        while(true)
        {
            LOG(LogLevel::DEBUG) << "我是一个测试方法";
            sleep(1);
        }
    }

    using thread_t = shared_ptr<Thread>;

    const static int defaultnum = 5;  // 默认创建五个线程

    template<typename T>
    class ThreadPool
    {
    private:
        bool isEmpty()
        {
            return _taskqueue.empty(); 
        }

        void HandlerTask(string name)
        {
            LOG(LogLevel::INFO) << "线程" << name << ", 进入HandlerTask的逻辑";
            while(true)
            {
                // 1.拿任务
                T t;
                {
                    LockGuard lockguard(_lock);
                    while(isEmpty() && _isrunning)
                    {
                        _wait_num++;
                        _cond.Wait(_lock);
                        _wait_num--;
                    }
                    // 只有当任务队列为空 && 线程不想运行了，表示线程池需要退出
                    if(isEmpty() && !_isrunning)
                        break;

                    t = _taskqueue.front();
                    _taskqueue.pop();
                }
                // 2.处理任务
                // 处理任务不需要加锁，不能在持有锁的期间处理任务，否则会降低效率
                t();  // 规定，未来所有的任务的处理，全部都是必须提供()方法
            }
            // 线程退出了，会跳出死循环,打印退出
            LOG(LogLevel::INFO) << "线程" << name << "退出";
        }
        ThreadPool(int num = defaultnum)
            :_num(num)
            ,_wait_num(0)
            ,_isrunning(false)
        {
            for(int i = 0;i < _num;i++)
            {
                _threads.push_back(make_shared<Thread>(bind(&ThreadPool::HandlerTask, this, placeholders::_1)));
                LOG(LogLevel::INFO) << "构建线程" << _threads.back()->Name() << "对象...成功";
            }
        }
    public:
        // 实现单例模式 
        static ThreadPool<T> *getInstance()
        {
            if (instance == NULL)
            {
                LockGuard lockguard(mutex);
                if (instance == NULL)
                {
                    LOG(LogLevel::INFO) << "单例首次被执行，需要加载对象...";
                    instance = new ThreadPool<T>();
                    instance->Start();
                }
            }

            return instance;
        }

        void Start()
        {
            if(_isrunning) return;  // 如果已经启动了，就返回
            _isrunning = true;
            for(auto& thread_ptr : _threads)
            {
                thread_ptr->Start();
                LOG(LogLevel::INFO) << "启动线程" << thread_ptr->Name() << "...成功";
            }
        }

        void Equeue(T& in)
        {
            LockGuard lockguard(_lock);
            if(!_isrunning) return;
            // _taskqueue.push(move(in));
            _taskqueue.push(in);
            if(_wait_num > 0)  // 进入了任务，如果有线程在wait，说明这个线程可以不用等待了，可以去做任务了
                _cond.Signal();
        }

        void Wait()
        {
            for(auto& thread_ptr : _threads)
            {
                thread_ptr->Join();
                LOG(LogLevel::INFO) << "回收线程" << thread_ptr->Name() << "...成功";
            }
        }

        // 线程池退出
        void Stop()
        {
            LockGuard lockguard(_lock);
            if(_isrunning)  // 在运行状态下退出
            {
                // 1. 不能有新增的任务
                _isrunning = false;
                // 2. 让线程自己退出（唤醒线程） && 历史的任务被全部处理完（taskqueue）
                if(_wait_num > 0)  // 只要taskqueue中有任务，线程就不可能等待,所以全部唤醒
                    _cond.BroadCast();
            }
        }
        ~ThreadPool()
        {}
    private:
        vector<thread_t> _threads;  // 管理每一个线程
        queue<T> _taskqueue;  // 任务队列,临界资源
        int _num;  // 线程数量
        Mutex _lock;  // 互斥锁
        Cond _cond;  // 条件变量，进行休眠的地方
        int _wait_num;  // 正在等待的线程个数
        bool _isrunning;  // 判断线程是不是在运行

        static ThreadPool<T> *instance;
        static Mutex mutex; // 只用来保护单例
    };
    template <typename T>
    ThreadPool<T> *ThreadPool<T>::instance = NULL;
    template <typename T>
    Mutex ThreadPool<T>::mutex; // 只用来保护单例
}